package me.youline.dataServer.service.front;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import me.youline.dataServer.controller.dto.notify.BaseActionNotifyMsgDTO;
import me.youline.dataServer.controller.dto.notify.FollowingActionNotifyMsgDTO;
import me.youline.dataServer.controller.dto.notify.PubMsgActionNotifyMsgDTO.PraiseActionNotifyMsgDTO;
import me.youline.dataServer.controller.dto.notify.SocialActionNotifyMsgListDTO;
import me.youline.dataServer.entity.socialActionMsg.MsgNotifyLatestRecord;
import me.youline.dataServer.entity.socialActionMsg.SocialActionBaseMsg;
import me.youline.dataServer.entity.socialActionMsg.SocialActionFollowingMsg;
import me.youline.dataServer.entity.socialActionMsg.SocialActionMsgNotifyRecord;
import me.youline.dataServer.entity.socialActionMsg.SocialActionMsgNotifyRecord.NotifyMsgType;
import me.youline.dataServer.entity.socialActionMsg.SocialActionPraiseMsg;
import me.youline.dataServer.service.LatestNotifyRecordService;
import me.youline.dataServer.service.SocialActionNotifyMsgService;
import me.youline.dataServer.service.support.file.FileLocatorManager;
import me.youline.dataServer.utils.IdPagination;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;

/**
 * 社交行为通知消息前端数据渲染业务类
 * 
 * @author linhan
 *
 */
@Service
public class SocialActionNotifyMsgDTOAdapter {

	@Autowired
	private SocialActionNotifyMsgService actionNotifyMsgService;
	
	@Autowired
	private LatestNotifyRecordService latestNotifyRecordService;

	@Autowired
	private UserInfoDTOAdapter userInfoDTOAdapter;

	@Autowired
	private SocialRelationDTOAdapter socialRelationDTOAdapter;

	@Autowired
	private FileLocatorManager fileLocatorManager;

	/**
	 * 获取通知消息数据列表
	 * 
	 * @param userId
	 * @param page
	 * @return
	 */
	public SocialActionNotifyMsgListDTO getNotifyMsgList(Long userId,
			IdPagination page) {
		// 无起始和结束id即客户端无数据获取的消息为最新，而客户端存在最新消息为endId
		if (((!page.hasEndId() && !page.hasStartId()))
				|| (page.hasEndId() && !page.hasStartId())) {
			return this.getLatestNotifyMsgsList(userId, page);
		} else {
			return this.getNotifyMsgsListDTO(userId, page);
		}
	}
	
	/**
	 * 根据用户ID与分页信息查询用户动态通知数据
	 * @param userId
	 * @param page
	 * @return
	 */
	protected  SocialActionNotifyMsgListDTO  getNotifyMsgsListDTO(Long userId,
			IdPagination page){
		List<SocialActionMsgNotifyRecord> records = actionNotifyMsgService
				.getSocialActionMsgsByUserId(userId, page);
		SocialActionNotifyMsgListDTO dto = new SocialActionNotifyMsgListDTO(userId);
		if(records.isEmpty()){
			return dto;
		}
		Map<Long, SocialActionMsgNotifyRecord> msgIdWithRecordMap = new LinkedHashMap<Long, SocialActionMsgNotifyRecord>();
		for (SocialActionMsgNotifyRecord s : records) {// 建立映射关系
			msgIdWithRecordMap.put(s.getMsgId(), s);
		}
		NotifyMsgClassification classification = new NotifyMsgClassification(records);//执行通知记录分类，以区分动态通知消息类型
		dto.setPraiseMsg(new PraiseMsgDTOHandler(userId, msgIdWithRecordMap, classification).getMsgDTOs());
		dto.setFollowingMsgs(new FollowingMsgDTOHandler(userId, msgIdWithRecordMap, classification).getMsgDTOs());
		return dto;
	}
	/**
	 * 获取最新通知消息列表
	 * 
	 * @param userId
	 * @param page
	 * @return
	 */
	protected SocialActionNotifyMsgListDTO getLatestNotifyMsgsList(Long userId,
			IdPagination page) {
		MsgNotifyLatestRecord r = latestNotifyRecordService
				.getMsgNotifyLatestRecord(userId);
		page.setStartId(r.getLatestNoticeId() == null ? IdPagination.NULL_ID_VALUE
				: r.getLatestNoticeId() + 1);
		SocialActionNotifyMsgListDTO dto = this.getNotifyMsgsListDTO(userId, page);
		latestNotifyRecordService.resetLatestMsgRecord(userId);
		return dto;
	}

	/**
	 * 通知消息分类器，可以将通知记录中的动态数据ID根据类型进行分类
	 * @author linhan
	 *
	 */
	class NotifyMsgClassification {
		
		private final List<Long> repostMsgIds = new ArrayList<Long>();
		private final List<Long> praiseMsgIds = new ArrayList<Long>();
		private final List<Long> followingMsgIds = new ArrayList<Long>();

		public NotifyMsgClassification(List<SocialActionMsgNotifyRecord> records) {
			for (SocialActionMsgNotifyRecord r : records) {
				if(r.getMsgType() == NotifyMsgType.PRAISE){
					praiseMsgIds.add(r.getMsgId());
				}else if(r.getMsgType() == NotifyMsgType.FOLLOWING){
					followingMsgIds.add(r.getMsgId());
				}
			}
		}

		public List<Long> getFollowingMsgIds() {
			return followingMsgIds;
		}

		public List<Long> getRepostMsgIds() {
			return repostMsgIds;
		}

		public List<Long> getPraiseMsgIds() {
			return praiseMsgIds;
		}
		
	}
	
	/**
	 * 通知动态数据DTO处理器，用于生成DTO列表
	 * @author linhan
	 *
	 * @param <T> 动态实体数据类型
	 * @param <M> 对应的动态DTO类型
	 */
	abstract class NotifyMsgDTOHandler<T extends SocialActionBaseMsg,M extends BaseActionNotifyMsgDTO>{
		
		protected List<Long> msgIds ;
		
		private Map<Long, SocialActionMsgNotifyRecord> msgIdWithRecordMap;
		
		protected Long userId ;
		
		public NotifyMsgDTOHandler(Long userId, Map<Long, SocialActionMsgNotifyRecord> msgIdWithRecordMap,NotifyMsgClassification classification){
			this.msgIds = this.getMsgIds(classification);
			this.msgIdWithRecordMap = msgIdWithRecordMap;
			this.userId = userId;
		}
		
		/**
		 * 获取动态DTO列表
		 * @return
		 */
		public List<M> getMsgDTOs(){
			List<? extends SocialActionBaseMsg> list  = this.getMsgs(msgIds);
			List<M> dtos = new ArrayList<M>();
			for(SocialActionBaseMsg msg : list){
				@SuppressWarnings("unchecked")
				M m = getMsgDTO((T)msg);
				m.setCreateTime(msg.getCreateTime());
				m.setId(msgIdWithRecordMap.get(msg.getId()).getId());
				m.setInitiator(userInfoDTOAdapter.getSimpleInfoDTO(msg
						.getInitiatorId()));
				dtos.add(m);
			}
			return dtos;
		}
		
		/**
		 * 将动态实体转换为动态DTO对象
		 * @param msg
		 * @return
		 */
		abstract protected M getMsgDTO(T msg);
			
		/**
		 * 从分类器中获取符合当前动态实体类型的数据列表
		 * @param classification
		 * @return
		 */
		abstract protected List<Long> getMsgIds(NotifyMsgClassification classification); 
		
		/**
		 * 获取动态数据实体列表
		 * @param msgIds
		 * @return
		 */
		abstract protected List<T> getMsgs(List<Long> msgIds);
	}
	
	
	
	/**
	 * 点赞动态DTO处理器，用于生成点赞动态DTO列表
	 * @author linhan
	 *
	 */
	class PraiseMsgDTOHandler extends NotifyMsgDTOHandler<SocialActionPraiseMsg,PraiseActionNotifyMsgDTO>{

		public PraiseMsgDTOHandler(Long userId,Map<Long, SocialActionMsgNotifyRecord> msgIdWithRecordMap,NotifyMsgClassification classification) {
			super(userId,msgIdWithRecordMap,classification);
		}

		@Override
		protected List<Long> getMsgIds(NotifyMsgClassification classification) {
			return classification.getPraiseMsgIds();
		}

		@SuppressWarnings("unchecked")
		@Override
		protected List<SocialActionPraiseMsg> getMsgs(List<Long> msgIds) {
			return (List<SocialActionPraiseMsg>) actionNotifyMsgService.getSocialActionMsgs(msgIds, NotifyMsgType.PRAISE);
		}


		@Override
		protected PraiseActionNotifyMsgDTO getMsgDTO(SocialActionPraiseMsg msg) {
			PraiseActionNotifyMsgDTO dto = new PraiseActionNotifyMsgDTO();
			dto.setPubMsgId(msg.getTargetId());
			dto.setPubMsgPic(fileLocatorManager.getDisplayPicFileLocator()
					.getFileWebUrl(msg.getMsgPicUrl()));
			return dto;
		}
	}
	
	/**
	 * 关注动态DTO处理器，用于生成关注动态DTO列表
	 * @author linhan
	 *
	 */
	class FollowingMsgDTOHandler extends NotifyMsgDTOHandler<SocialActionFollowingMsg,FollowingActionNotifyMsgDTO>{

		public FollowingMsgDTOHandler(Long userId,Map<Long, SocialActionMsgNotifyRecord> msgIdWithRecordMap, NotifyMsgClassification classification) {
			super(userId,msgIdWithRecordMap,classification);
		}

		@Override
		protected List<Long> getMsgIds(NotifyMsgClassification classification) {
			return classification.getFollowingMsgIds();
		}

		@SuppressWarnings("unchecked")
		@Override
		protected List<SocialActionFollowingMsg> getMsgs(List<Long> msgIds) {
			return  (List<SocialActionFollowingMsg>) actionNotifyMsgService.getSocialActionMsgs(msgIds, NotifyMsgType.FOLLOWING);
		}

		@Override
		protected FollowingActionNotifyMsgDTO getMsgDTO(
				SocialActionFollowingMsg msg) {
			FollowingActionNotifyMsgDTO dto = new FollowingActionNotifyMsgDTO();
			dto.setSocialRel(socialRelationDTOAdapter.getSocialRelDTOForUser(
					userId,
					Lists.newArrayList(msg.getInitiatorId())));
			return dto;
		}
	}
}
